package com.vogtec.fota.mqtt;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.vogtec.fota.config.Config;
import com.vogtec.fota.dao.BikeDao;
import com.vogtec.fota.dao.UpgradeTaskDao;
import com.vogtec.fota.dao.model.Bike;
import com.vogtec.fota.entity.mqtt.*;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.List;

/**
 * Created by TieYan on 2016/6/29.
 */
@Component("mqttHandler")
@Scope("prototype")
@Slf4j
public class MqttMessageHandler implements Runnable {
	private String topic;
	private MqttMessage message;

	@Autowired
	private BikeDao bikeDao;
	@Autowired
	private UpgradeTaskDao upgradeTaskDao;
	@Autowired
	private ObjectMapper objectMapper;
	@Autowired
	private BikeEmqttClient bikeEmqttClient;

	public void init(String topic, MqttMessage message) {
		this.topic = topic;
		this.message = message;
	}

	@Override
	public void run() {
		log.debug("\n< < < < < < < Mqtt message arrived topic = " + topic + " length=" + message.getPayload().length + " < < < < < < < < <");
		log.debug(Arrays.toString(message.getPayload()));
		log.debug("< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < ");

			switch (topic) {
				case "vogtec/gx/fota/ack":
					log.debug("111111111111");
					processAck(message.getPayload());
					break;
				case "vogtec/gx/version/info":
					log.debug("333333333333");
					processCheckVersion(message.getPayload());
					break;
				default:
					log.debug("222222222222");
					processReconnect(message.getPayload());
			}
	}

	private void processAck(byte[] content){
		BikeFotaAck ack = new BikeFotaAck();
		try{
			ack.decode(content);
		}catch (BikeWireFormatError | UnsupportedEncodingException e){
			e.printStackTrace();
			log.warn("",e);
		}
		log.info("Report : BikeNum = [" + ack.getBikeNum() + "] UPGRADE ACK");

		if(upgradeTaskDao.selectByid(Config.taskId).getCompletion().equals("0.0"))
			upgradeTaskDao.updateCompletion("0.1",Config.taskId);

//		Bike bike = bikeDao.selectBikesLatest(ack.getBikeNum());
//
//		bikeDao.updateStatusByUpgrade_task(1,bike.getUpgradeTask());

//		bikeDao.updateStatusByUpgrade_task(1, Config.taskId);

	}

	private void processCheckVersion(byte[] content){
		BikeFotaVersionInfo fotaVersionInfo = new BikeFotaVersionInfo();
		try{
			fotaVersionInfo.decode(content);
		}catch (UnsupportedEncodingException | BikeWireFormatError e){
			e.printStackTrace();
			log.warn("",e);
		}
		log.debug("CheckVersion : BikeNum = [" + fotaVersionInfo.getBikeNum() + "] CHECK VERSION" );

		//根据bikeNum找到最近一次处理过的bike，取其upgradeTask即为'upgradeTask'表的id，根据id找到对应的任务，取其版本号
//		int upgradeTask = bikeDao.selectBikesLatest(fotaVersionInfo.getBikeNum()).getUpgradeTask();

		log.debug("CheckVersion : upgradeTask = ["+ Config.taskId +"] CHECK VERSION");

		String versionTarget = upgradeTaskDao.selectByid(Config.taskId).getFirmWareVersion();

		log.info("CheckVersion : versionTarger = ["+ versionTarget +"] , version = [" + fotaVersionInfo.getVersion() + "] CHECK VERSION");

		if(fotaVersionInfo.getVersion().equals(versionTarget)){
			bikeDao.updateStatusByUpgrade_task(3, Config.taskId);
			log.info("Upgrade Complete : BikeNum = [" + fotaVersionInfo.getBikeNum() + "]");
		}

		//此处可能需要换成decimal  或换成整形存储传输
		double count = bikeDao.selectBikeCount(Config.taskId);
		double completeCount = bikeDao.selectStatusCount(Config.taskId,3);

		log.debug("Count : [{}] , CompleteCount : [{}] ",count,completeCount);

		//更新完成率
		String completion = String.valueOf(completeCount/count);
		Double comp = Double.valueOf(completion)*0.8 + 0.2;
		upgradeTaskDao.updateCompletion(String.format("%.2f",comp), Config.taskId);
		log.info("Upgrade Complete : Completion = [" + completion + "]");

		//更新状态
//		if(completeCount > 0 && completeCount != count){
//			upgradeTaskDao.updateStatus(1, Config.taskId);
//			log.info("Upgrade Complete : Status = [" + 1 + "]");
//		}
		/*else */if(completeCount == count){
			upgradeTaskDao.updateStatus(2, Config.taskId);

			Timestamp compTime = new Timestamp(System.currentTimeMillis());
			upgradeTaskDao.updateCompTime(compTime, Config.taskId);

			Config.taskId = null;
			log.debug("Upgrade Complete : Status = [" + 2 + "]");
		}
	}

	private void processReconnect(byte[] content){
		ClientConnect clientConnect = null;
		try{
			clientConnect = objectMapper.readValue(content, ClientConnect.class);
		}catch (IOException e){
			e.printStackTrace();
		}

		//不是以"bike:"开头的不做处理
		if(clientConnect.getUsername().substring(0,5).equals("bike:")){
			String bikeNum = clientConnect.getUsername().substring(5);

			List<String> bikeNums = bikeDao.selectBikeNumById(Config.taskId);

			//不在本次升级任务中的不做处理
			if(bikeNums.contains(bikeNum)){
				log.info(clientConnect.toString());
				Bike bike = bikeDao.selectBikeByIdBikeNum(bikeNum, Config.taskId);

				//此处可能出现bug，需改成"1or2"
				if(bike.getStatus() == 1){
					log.info("Reconnected: BikeNum = [" + bike.getBikeNum() + "] UPGRADE RECONNECT");

					bikeDao.updateStatusByUpgrade_task(2,bike.getUpgradeTask());
					upgradeTaskDao.updateCompletion("0.2",Config.taskId);

					//此处发送版本信息确认指令
					BikeReportVersionInvo reportVersionInvo = new BikeReportVersionInvo(bikeNum);
					byte[] versionCon = reportVersionInvo.encode();

					try{
						bikeEmqttClient.publish(versionCon,"$client/bike:" + bikeNum);
					}catch (MqttException e){
						e.printStackTrace();
						log.warn("",e);
					}
				}
			}
		}
	}
}